#ifndef __BLOCK_QUEUE_HPP__
#define __BLOCK_QUEUE_HPP__

#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>

template <class T>
class BlockQueue
{
private:
    bool IsFull()
    {
        return _block_queue.size() == _cap;
    }

    bool IsEmpty()
    {
        return _block_queue.empty();
    }

public:
    BlockQueue(int cap)
        : _cap(cap)
    {
    }

    void EnQueue(T &in) // 生产者需要的接口：入队
    {
        pthread_mutex_lock(&_mutex);
        if (IsFull())
        {
            // 阻塞队列满了，不能再入队了，所以等待，同时释放mutex,让消费者可以从队列里拿数据
            pthread_cond_wait(&_product_cond, &_mutex);
        }
        _block_queue.push(in);
        pthread_cond_signal(&_consumer_cond); // 通知消费者
        pthread_mutex_unlock(&_mutex);        // 解锁
    }

    void PopQueue() // 消费者需要的接口：出队，拿数据
    {
        pthread_mutex_lock(&_mutex);
        if (IsEmpty())
        {
            // 阻塞队列空了，不能再拿数据队了，所以等待，同时释放mutex,让生产者可以向队列里插入数据
            pthread_cond_wait(&_consumer_cond, &_mutex);
        }
        _block_queue.push(in);
        pthread_cond_signal(&_product_cond); // 通知生产者
        pthread_mutex_unlock(&_mutex);       // 解锁
    }

private:
    std::queue<T> _block_queue;    // 阻塞队列
    int _cap;                      // 最大容量
    pthread_mutex_t _mutex;        // 对阻塞队列加锁
    pthread_cond_t _product_cond;  // 给生产者提供的条件变量
    pthread_cond_t _consumer_cond; // 给消费者提供的条件变量
};

#endif